#pragma once

//#ifndef _WIN32_WINNT
//#define _WIN32_WINNT 0x0500
//#endif
//
//#ifndef _COMPILER_VS_NET
//#define _COMPILER_VS_NET
//#endif

#include "SafeStr.h"
#include "SafeWcs.h"
#include <Base/CriticalRw.h>
#include <Base/CriticalSection.h>


class SafeRecord;
class SafeSP;

enum SPTYPE
{
	SP_IN = 1,
	SP_OUT,
	SP_INOUT,
	SP_RET,
};


class SafeDB: public __OCF_BASE__::CCritical
{
public:
	SafeDB();
	virtual ~SafeDB();

	void SetInfo(LPCSTR szConnString);
	char *GetInfo();

	virtual bool Open() = 0;
	virtual void Close() = 0;

	virtual bool Execute(LPCSTR sql);
	virtual bool Execute(LPCSTR sql, SafeRecord* record);

	virtual bool Prepare(LPCSTR storedProc, SafeSP* sp);

	virtual bool Transact();
	virtual bool Rollback();
	virtual bool Commit();

	virtual void _OnError(int code, LPCSTR from, LPCSTR msg);

protected:
	StrConnString		_connString;
};


struct SysTime : public SYSTEMTIME
{
	CHAR		_dummy[40];
};


class SafeRecord
{
public:
	SafeRecord();
	virtual ~SafeRecord();

	virtual bool IsAlloc() = 0;
	virtual void Free() = 0;

	virtual bool Prev();
	virtual bool Next();
	virtual bool More();

	virtual bool Data(USHORT column, char& val);
	virtual bool Data(USHORT column, unsigned char& val);
	virtual bool Data(USHORT column, short int& val);
	virtual bool Data(USHORT column, unsigned short int& val);
	virtual bool Data(USHORT column, int &val);
	virtual bool Data(USHORT column, unsigned int& val);
	virtual bool Data(USHORT column, long& val);
	virtual bool Data(USHORT column, unsigned long& val);
	virtual bool Data(USHORT column, __int64& val);
	virtual bool Data(USHORT column, unsigned __int64& val);
	virtual bool Data(USHORT column, float& val);
	virtual bool Data(USHORT column, double& val);
	virtual bool Data(USHORT column, char* buf, int bufMaxLen);
	virtual bool Data(USHORT column, wchar_t* buf, int bufMaxLen);
	virtual bool Data(USHORT column, unsigned char* buf, int bufMaxLen);
	virtual bool Data(USHORT column, SysTime& sysTime);
	virtual bool Data(USHORT column, StrName& name);
	virtual bool Data(USHORT column, StrPath& path);
	virtual bool Data(USHORT column, StrMsg& msg);
	virtual bool Data(USHORT column, WcsName& name);
	virtual bool Data(USHORT column, WcsPath& path);
	virtual bool Data(USHORT column, WcsMsg& msg);

	virtual bool Data(USHORT column, char* buf, int bufMaxLen, int &bufLen);
	virtual bool Data(USHORT column, wchar_t* buf, int bufMaxLen, int &bufLen);
	virtual bool Data(USHORT column, unsigned char* buf, int bufMaxLen, int &bufLen);

	SafeDB*		_db;
	void*		_rec;
};


class SafeSP
{
public:
	SafeSP();
	virtual ~SafeSP();

	virtual bool IsAlloc() = 0;
	virtual void Free() = 0;

	virtual bool Bind(USHORT column, SPTYPE type, char& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned char& val);
	virtual bool Bind(USHORT column, SPTYPE type, short int& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned short int& val);
	virtual bool Bind(USHORT column, SPTYPE type, int& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned int& val);
	virtual bool Bind(USHORT column, SPTYPE type, long& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned long& val);
	virtual bool Bind(USHORT column, SPTYPE type, __int64& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned __int64& val);
	virtual bool Bind(USHORT column, SPTYPE type, float& val);
	virtual bool Bind(USHORT column, SPTYPE type, double& val);
	virtual bool Bind(USHORT column, SPTYPE type, const char* str);
	virtual bool Bind(USHORT column, SPTYPE type, const wchar_t* str);
	virtual bool Bind(USHORT column, SPTYPE type, char* buf, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, wchar_t* buf, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned char* bin, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, SysTime& sysTime);
	virtual bool Bind(USHORT column, SPTYPE type, StrName& name);
	virtual bool Bind(USHORT column, SPTYPE type, StrPath& path);
	virtual bool Bind(USHORT column, SPTYPE type, StrMsg& msg);
	virtual bool Bind(USHORT column, SPTYPE type, WcsName& name);
	virtual bool Bind(USHORT column, SPTYPE type, WcsPath& path);
	virtual bool Bind(USHORT column, SPTYPE type, WcsMsg& msg);

	virtual bool Execute();
	virtual bool Execute(SafeRecord* record);

	SafeDB*		_db;
	void*		_sp;
	StrPath		_spName;
};


class SafeDBAutoLock
{
public:
	SafeDBAutoLock(SafeDB& db);
	~SafeDBAutoLock();

	SafeDB& _db;
};


//////////////////////////////////////////////////////////////////////////

#pragma comment(lib, "odbc32.lib")


#define MAX_ODBC_SP_PARAM	64
#define MAX_ODBC_ERR		5
#define MAX_ODBC_ERROR_SIZE	1024


class OdbcErr
{
public:
	OdbcErr(){ m_szError[0] = 0; }

	virtual void _OnError(int code, LPCSTR from, LPCSTR msg);
	inline char *GetError(){ return m_szError; }

private:
	char m_szError[MAX_ODBC_ERROR_SIZE];
};


class OdbcDB : public SafeDB
{
public:
	OdbcDB();
	virtual ~OdbcDB();

	void SetError(OdbcErr* err);

	virtual bool Open();
	virtual void Close();
	
	virtual bool Execute(LPCSTR sql);
	virtual bool Execute(LPCSTR sql, SafeRecord* record);

	virtual bool Prepare(LPCSTR storedProc, SafeSP* sp);

	virtual bool Rollback();
	virtual bool Commit();

	virtual void _OnError(int code, LPCSTR from, LPCSTR msg);
	virtual char *GetError();

	virtual bool Ping();

	bool _Error(short handleType, void* handle, LPCSTR at);
	void _ErrorEnv(LPCSTR from);
	void _ErrorOdbc(LPCSTR from);
	bool _ErrorStmt(void* handle, LPCSTR from);
	void _GetParamInfo(void* handle, StrMsg& msg);
	bool _IsLive();

	static void Update(SysTime& sysTime, bool bGet=true);

	void Lock()		{ SafeDB::Lock(); }
	void Unlock()	{ SafeDB::Unlock(); }
	

protected:
	void*		_env;
	void*		_odbc;
	OdbcErr*	_err;

private:
	DWORD		_lastPingTime;
};


class OdbcRecord : public SafeRecord
{
public:
	OdbcRecord();
	virtual ~OdbcRecord();

	virtual bool IsAlloc();
	virtual void Free();

	virtual bool Next();
	virtual bool More();

	virtual bool Data(USHORT column, char& val);
	virtual bool Data(USHORT column, unsigned char& val);
	virtual bool Data(USHORT column, short int& val);
	virtual bool Data(USHORT column, unsigned short int& val);
	virtual bool Data(USHORT column, int& val);
	virtual bool Data(USHORT column, unsigned int& val);
	virtual bool Data(USHORT column, long& val);
	virtual bool Data(USHORT column, unsigned long& val);
	virtual bool Data(USHORT column, __int64& val);
	virtual bool Data(USHORT column, unsigned __int64& val);
	virtual bool Data(USHORT column, float& val);
	virtual bool Data(USHORT column, double& val);
	virtual bool Data(USHORT column, char* buf, int bufMaxLen);
	virtual bool Data(USHORT column, wchar_t* buf, int bufMaxLen);
	virtual bool Data(USHORT column, unsigned char* buf, int bufMaxLen);
	virtual bool Data(USHORT column, SysTime& sysTime);
	virtual bool Data(USHORT column, StrName& name);
	virtual bool Data(USHORT column, StrPath& path);
	virtual bool Data(USHORT column, StrMsg& msg);
	virtual bool Data(USHORT column, WcsName& name);
	virtual bool Data(USHORT column, WcsPath& path);
	virtual bool Data(USHORT column, WcsMsg& msg);

	virtual bool Data(USHORT column, char* buf, int bufMaxLen, int &bufLen);
	virtual bool Data(USHORT column, wchar_t* buf, int bufMaxLen, int &bufLen);
	virtual bool Data(USHORT column, unsigned char* buf, int bufMaxLen, int &bufLen);
};


class OdbcSP : public SafeSP
{
public:
	OdbcSP();
	virtual ~OdbcSP();

	virtual bool IsAlloc();
	virtual void Free();

	virtual bool Bind(USHORT column, SPTYPE type, char& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned char& val);
	virtual bool Bind(USHORT column, SPTYPE type, short int& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned short int& val);
	virtual bool Bind(USHORT column, SPTYPE type, int& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned int& val);
	virtual bool Bind(USHORT column, SPTYPE type, long& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned long& val);
	virtual bool Bind(USHORT column, SPTYPE type, __int64& val);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned __int64& val);
	virtual bool Bind(USHORT column, SPTYPE type, float& val);
	virtual bool Bind(USHORT column, SPTYPE type, double& val);
	virtual bool Bind(USHORT column, SPTYPE type, const char* str);
	virtual bool Bind(USHORT column, SPTYPE type, const wchar_t* str);
	virtual bool Bind(USHORT column, SPTYPE type, char* buf, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, wchar_t* buf, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, unsigned char* bin, int bufLen, int bufMaxLen);
	virtual bool Bind(USHORT column, SPTYPE type, SysTime& sysTime);
	virtual bool Bind(USHORT column, SPTYPE type, StrName& name);
	virtual bool Bind(USHORT column, SPTYPE type, StrPath& path);
	virtual bool Bind(USHORT column, SPTYPE type, StrMsg& msg);
	virtual bool Bind(USHORT column, SPTYPE type, WcsName& name);
	virtual bool Bind(USHORT column, SPTYPE type, WcsPath& path);
	virtual bool Bind(USHORT column, SPTYPE type, WcsMsg& msg);

	virtual bool Execute();
	virtual bool Execute(SafeRecord* record);

	long* GetLenPtr(long val)
	{
		long* ptr = &StrLen[StrLenCount++];
		*ptr = val;
		return ptr;
	}

	long StrLen[MAX_ODBC_SP_PARAM];
	long StrLenCount;
};
